package org.jsola.hr.provider.impl;

import lombok.extern.slf4j.Slf4j;
import org.jsola.exception.ParamException;
import org.jsola.hr.constant.HrConstants;
import org.jsola.hr.dto.ChildCompanyAddDTO;
import org.jsola.hr.dto.ChildCompanyUpdateDTO;
import org.jsola.hr.dto.GroupCompanyAddDTO;
import org.jsola.hr.entity.DepInfoDO;
import org.jsola.hr.entity.EmpDepDO;
import org.jsola.hr.entity.EmpInfoDO;
import org.jsola.hr.entity.GroupCompanyDO;
import org.jsola.hr.provider.IPermissionGroupProviderService;
import org.jsola.hr.provider.IPermissionProviderService;
import org.jsola.hr.provider.IUserProviderService;
import org.jsola.hr.service.*;
import org.jsola.hr.vo.ChildCompanyVO;
import org.jsola.hr.vo.CompanyVO;
import org.jsola.hr.vo.HrUserVO;
import org.jsola.permission.dto.GroupAddDTO;
import org.jsola.permission.dto.GroupUpdateDTO;
import org.jsola.permission.dto.GroupUserAddDTO;
import org.jsola.permission.dto.GroupUserUpdateDTO;
import org.jsola.permission.entity.GroupDO;
import org.jsola.permission.entity.GroupUserDO;
import org.jsola.permission.query.GroupQuery;
import org.jsola.permission.service.IGroupService;
import org.jsola.permission.service.IGroupUserService;
import org.jsola.permission.vo.GroupListVO;
import org.jsola.permission.vo.GroupUserVO;
import org.jsola.permission.vo.GroupVO;
import org.jsola.user.core.TokenUser;
import org.jsola.user.query.UserQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
 * @author june
 */
@Service("hrPermissionGroupProviderService")
@Slf4j
public class PermissionGroupProviderServiceImpl implements IPermissionGroupProviderService {

    @Autowired
    private IGroupService groupService;

    @Autowired
    private IGroupUserService groupUserService;

    @Autowired
    private IDepInfoService depInfoService;

    @Autowired
    private IEmpDepService empDepService;

    @Autowired
    private IEmpInfoService empInfoService;

    @Autowired
    private IUserProviderService userProviderService;

    @Autowired
    private IGroupCompanyService groupCompanyService;

    @Autowired
    private ICompanyService companyService;

    private final String CODE_LEADER = "leader";


    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public void saveGroupByDep(DepInfoDO depInfoDO, TokenUser tokenUser) {
        // 根据hr部门构建权限组信息
        GroupAddDTO groupDO = buildGroupByDepInfo(depInfoDO);
        groupService.saveById(groupDO, depInfoDO.getId(), tokenUser);

        // 负责人
        if (!StringUtils.isEmpty(depInfoDO.getLeader())) {
            boolean userExis = checkUserExis(depInfoDO.getId(), depInfoDO.getLeader(), tokenUser.getSiteId());
            if (userExis) {
                // 用户存在
                // 保存部门管理人
                addGroupLeader(depInfoDO.getId(), depInfoDO.getLeader(), tokenUser);
            } else {
                // 不存在,直接添加
                GroupUserAddDTO groupUserAddDTO = new GroupUserAddDTO();
                groupUserAddDTO.setGroupId(depInfoDO.getId());
                groupUserAddDTO.setUserId(depInfoDO.getLeader());
                groupUserAddDTO.setType(CODE_LEADER);
                groupUserService.save(groupUserAddDTO, tokenUser);
            }
        }
    }


    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public void updateGroup(String groupId, TokenUser tokenUser) {
        DepInfoDO depInfoDO = depInfoService.selectDOById(groupId, tokenUser.getSiteId());
        if (Objects.isNull(depInfoDO)) {
            return;
        }
        GroupDO groupDO = groupService.selectDOById(groupId, tokenUser.getSiteId());
        if (Objects.isNull(groupDO)) {
            // 没有新增
            saveGroupByDep(depInfoDO, tokenUser);
        } else {
            // 负责人
            String leadUserId = depInfoDO.getLeader();
            // 修改
            GroupAddDTO groupAddDTO = buildGroupByDepInfo(depInfoDO);
            GroupUpdateDTO groupUpdateDTO = groupAddDTO.to(GroupUpdateDTO.class);
            groupUpdateDTO.setId(depInfoDO.getId());
            groupService.update(groupUpdateDTO, tokenUser);
            // 管理员
            List<String> userIds = groupUserService.listUserByGroupType(groupDO.getId(), CODE_LEADER, tokenUser.getSiteId());
            if (StringUtils.isEmpty(leadUserId)) {
                // 取消负责人且权限有负责人
                if (!CollectionUtils.isEmpty(userIds)) {
                    addGroupLeader(depInfoDO.getId(), depInfoDO.getLeader(), tokenUser);
                }
            } else {
                // 负责人不一致
                if (CollectionUtils.isEmpty(userIds) || !leadUserId.equals(userIds.get(0))) {
                    addGroupLeader(depInfoDO.getId(), depInfoDO.getLeader(), tokenUser);
                }
            }
        }
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public void deleteGroupByIds(String[] depInfoIds, TokenUser tokenUser) {
        groupService.deleteByIds(tokenUser, depInfoIds);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public void saveGroupUserByDep(EmpDepDO empDepDO, TokenUser tokenUser) {
        GroupUserDO groupUserDO = buildGroupUserByEmpDep(empDepDO, tokenUser);
        if (Objects.isNull(groupUserDO)) {
            return;
        }
        // 保存用户与组关系
        saveGroupUser(groupUserDO, tokenUser);
    }

    /**
     * 保存用户与组关系
     *
     * @param groupUserDO 用户组关系
     * @param tokenUser   当前用户
     */
    private void saveGroupUser(GroupUserDO groupUserDO, TokenUser tokenUser) {
        // 校验是否已存在
        GroupUserVO groupUserCheck = groupUserService.findGroupUserByGroupAndUser(groupUserDO.getGroupId(), groupUserDO.getUserId(), tokenUser.getSiteId());
        if (Objects.isNull(groupUserCheck)) {
            GroupUserAddDTO groupUserAddDTO = groupUserDO.to(GroupUserAddDTO.class);
            groupUserService.save(groupUserAddDTO, tokenUser);
        } else {
            GroupUserUpdateDTO groupUserUpdateDTO = groupUserDO.to(GroupUserUpdateDTO.class);
            groupUserUpdateDTO.setId(groupUserCheck.getId());
            groupUserService.update(groupUserUpdateDTO, tokenUser);
        }
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public void updateGroupUser(String groupUserId, TokenUser tokenUser) {
        EmpDepDO empDepDO = empDepService.selectDOById(groupUserId, tokenUser.getSiteId());
        if (Objects.isNull(empDepDO)) {
            return;
        }
        saveGroupUserByDep(empDepDO, tokenUser);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public void deleteGroupUser(String[] groupUserIds, TokenUser tokenUser) {
        for (String groupUserId : groupUserIds) {
            EmpDepDO empDepDO = empDepService.selectDOById(groupUserId, tokenUser.getSiteId());
            // 根据部门成员关联删除权限的部门员工关联
            deletePmGroupUserByEmpDep(empDepDO, tokenUser);
        }
    }

    /**
     * 根据部门成员关联删除权限的部门员工关联
     *
     * @param empDepDO  部门成员关联
     * @param tokenUser 当前用户
     */
    private void deletePmGroupUserByEmpDep(EmpDepDO empDepDO, TokenUser tokenUser) {
        if (Objects.isNull(empDepDO)) {
            return;
        }
        GroupUserDO groupUserDO = buildGroupUserByEmpDep(empDepDO, tokenUser);
        if (Objects.isNull(groupUserDO)) {
            return;
        }
        // 权限关联关系删除
        groupUserService.deleteGroupUserByGroupAndUser(groupUserDO.getGroupId(), groupUserDO.getUserId(), tokenUser);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public void updateUsersGroup(List<EmpDepDO> oldEmpDepList, List<EmpDepDO> newEmpDepList, TokenUser tokenUser) {
        // 删除旧的关联关系
        if (!CollectionUtils.isEmpty(oldEmpDepList)) {
            oldEmpDepList.forEach(
                    empDepDO -> {
                        // 根据部门成员关联删除权限的部门员工关联
                        deletePmGroupUserByEmpDep(empDepDO, tokenUser);
                    }
            );
        }
        // 增加新的关联关系
        if (!CollectionUtils.isEmpty(newEmpDepList)) {
            newEmpDepList.forEach(
                    empDepDO -> saveGroupUserByDep(empDepDO, tokenUser)
            );
        }

    }

    @Override
    public GroupDO selectDOById(String groupId, String siteId) {
        return groupService.selectDOById(groupId, siteId);
    }

    @Override
    public List<GroupListVO> select(GroupQuery groupQuery, String siteId) {
        return groupService.select(groupQuery, siteId);
    }


    /**
     * 根据hr部门构建权限组信息
     *
     * @param depInfoDO hr部门
     * @return 权限模块组信息
     */
    private GroupAddDTO buildGroupByDepInfo(DepInfoDO depInfoDO) {
        GroupAddDTO groupAddDO = new GroupAddDTO();
        groupAddDO.setName(depInfoDO.getName());
        groupAddDO.setDescription(depInfoDO.getDesc());
        groupAddDO.setParentId(depInfoDO.getParentId());
        groupAddDO.setSort(depInfoDO.getSort());

        return groupAddDO;
    }

    /**
     * 根据hr部门成员关系构建权限组与成员关系
     *
     * @param empDepDO  hr部门成员关系
     * @param tokenUser 当前用户
     * @return 权限组与成员关系
     */
    private GroupUserDO buildGroupUserByEmpDep(EmpDepDO empDepDO, TokenUser tokenUser) {
        // 部门
        DepInfoDO depInfoDO = depInfoService.selectDOById(empDepDO.getDepId(), tokenUser.getSiteId());
        if (Objects.isNull(depInfoDO)) {
            return null;
        }
        // 员工
        EmpInfoDO empInfoDO = empInfoService.selectDOById(empDepDO.getEmpId(), tokenUser.getSiteId());
        if (Objects.isNull(empInfoDO)) {
            return null;
        }
        if (StringUtils.isEmpty(empInfoDO.getUserId())) {
            return null;
        }
        // 权限部门成员关系
        GroupUserDO groupUserDO = new GroupUserDO();
        groupUserDO.setGroupId(empDepDO.getDepId());
        groupUserDO.setUserId(empInfoDO.getUserId());
        if (!StringUtils.isEmpty(depInfoDO.getLeader())
                && empDepDO.getEmpId().equals(depInfoDO.getLeader())) {
            groupUserDO.setType(CODE_LEADER);
        } else {
            groupUserDO.setType("");
        }
        return groupUserDO;
    }

    /**
     * 保存部门管理人
     *
     * @param groupId   组id
     * @param userId    用户id
     * @param tokenUser 用户
     */
    private void addGroupLeader(String groupId, String userId, TokenUser tokenUser) {
        // 取消之前负责人
        groupUserService.removeGroupUserType(groupId, CODE_LEADER, tokenUser);
        if (StringUtils.isEmpty(userId)) {
            return;
        }
        // 给该人员附上管理权限
        groupUserService.addGroupUserType(groupId, Collections.singletonList(userId), CODE_LEADER, tokenUser);
    }

    /**
     * 校验组内用户是否存在
     *
     * @param groupId 组id
     * @param userId  用户id
     * @param siteId  站点
     * @return 用户是否存在
     */
    private boolean checkUserExis(String groupId, String userId, String siteId) {
        GroupUserVO groupUserVO = groupUserService.findGroupUserByGroupAndUser(groupId, userId, siteId);
        return !Objects.isNull(groupUserVO);
    }

    @Override
    public ChildCompanyVO saveGroupByChildCompany(ChildCompanyAddDTO childCompanyAdd, String childCompanyId, TokenUser tokenUser) {
        ChildCompanyVO childCompanyVO = new ChildCompanyVO();

        // 构建组
        GroupAddDTO groupAddDTO = new GroupAddDTO();
        groupAddDTO.setName(childCompanyAdd.getName());
        groupAddDTO.setParentId("0");
        // 保存组
        GroupVO groupVO = groupService.saveById(groupAddDTO, childCompanyId, tokenUser);
        childCompanyVO.setGroupVO(groupVO);

        // 发布分管单位
        publishChildCompany(groupVO.getId(), childCompanyAdd.getIsAllCompany(), childCompanyAdd.getManagedCompanyList(), tokenUser);

        return childCompanyVO;
    }

    @Override
    public ChildCompanyVO updateGroupByChildCompany(ChildCompanyUpdateDTO childCompanyUpdate, String childCompanyId, TokenUser tokenUser) {
        ChildCompanyVO childCompanyVO = new ChildCompanyVO();

        GroupDO groupDO = selectDOById(childCompanyUpdate.getId(), tokenUser.getSiteId());
        ParamException.notNull(groupDO, "子公司分组不存在或已删除");

        // 修改分组名称
        GroupUpdateDTO groupUpdateDTO = new GroupUpdateDTO();
        groupUpdateDTO.setId(groupDO.getId());
        groupUpdateDTO.setName(childCompanyUpdate.getName());
        groupService.update(groupUpdateDTO, tokenUser);

        // 组
        GroupVO groupVO = groupService.selectById(groupDO.getId(), tokenUser.getSiteId());
        childCompanyVO.setGroupVO(groupVO);

        // 发布分管单位
        publishChildCompany(groupVO.getId(), childCompanyUpdate.getIsAllCompany(), childCompanyUpdate.getManagedCompanyList(), tokenUser);

        return childCompanyVO;
    }

    @Override
    public void deleteChildCompany(String groupId, TokenUser tokenUser) {
        GroupDO groupDO = selectDOById(groupId, tokenUser.getSiteId());
        ParamException.notNull(groupDO, "子公司分组不存在或已删除");

        // 移除组分管单位,分为删除数据,移除组子公司管理员身份
        removeGroupChildCompany(groupId, tokenUser);
    }

    @Override
    public ChildCompanyVO findChildCompanyById(ChildCompanyVO childCompany, String siteId) {
        String groupId = childCompany.getId();
        GroupVO group = groupService.selectById(groupId, siteId);
        ParamException.notNull(group, "子公司分组不存在或已删除");

        // 组
        childCompany.setGroupVO(group);

        // 公司下管理人员
        List<HrUserVO> hrUserList = userProviderService.queryUserList(new UserQuery(), groupId, siteId);
        // 子公司管理员,组内员工
        childCompany.setAdminUserList(hrUserList);

        // 组分管单位
        childCompany.setIsAllCompany(false);
        List<GroupCompanyDO> groupCompanyList = groupCompanyService.listByGroupId(groupId, siteId);
        if (!CollectionUtils.isEmpty(groupCompanyList)) {
            GroupCompanyDO isAllGroupCompany = groupCompanyList.parallelStream()
                    .filter(GroupCompanyDO::getIsAll)
                    .findFirst().orElse(null);
            if (Objects.nonNull(isAllGroupCompany)) {
                // 全部用工单位
                childCompany.setIsAllCompany(true);
                // 全部用工单位
                List<CompanyVO> companyList = companyService.listVoByIds(siteId, (String[]) null);
                childCompany.setCompanyList(companyList);
            } else {
                // 具体用工单位
                String[] companyIds = groupCompanyList.parallelStream()
                        .map(GroupCompanyDO::getCompanyId)
                        .distinct()
                        .toArray(String[]::new);
                if (companyIds.length > 0) {
                    List<CompanyVO> companyList = companyService.listVoByIds(siteId, companyIds);
                    childCompany.setCompanyList(companyList);
                }
            }
        }

        return childCompany;
    }

    /**
     * 发布分管单位,先移除旧的,再添加信息
     *
     * @param groupId       组id
     * @param isAll         全部用工单位
     * @param companyIdList 公司id
     * @param tokenUser     当前用户
     */
    private void publishChildCompany(String groupId, Boolean isAll, List<String> companyIdList, TokenUser tokenUser) {
        if (isAll == null) {
            isAll = false;
        }
        if (!isAll && CollectionUtils.isEmpty(companyIdList)) {
            return;
//            ParamException.notEmpty(companyIdList, "非全部用工单位时,请传递分公司分管的具体的用工单位");
        }

        // 移除组分管单位,分为删除数据,移除组子公司管理员身份
        removeGroupChildCompany(groupId, tokenUser);

        if (isAll) {
            // 分管公司
            GroupCompanyAddDTO groupCompanyAdd = new GroupCompanyAddDTO();
            groupCompanyAdd.setGroupId(groupId);
            groupCompanyAdd.setIsAll(true);
            groupCompanyAdd.setCompanyId("all");
            groupCompanyService.save(groupCompanyAdd, tokenUser);
        } else {
            // 旧的组人员操作时已处理,直接保存新的
            if (!CollectionUtils.isEmpty(companyIdList)) {
                List<GroupCompanyAddDTO> groupCompanyAddList = new ArrayList<>();
                for (String companyId : companyIdList) {
                    CompanyVO childCompany = companyService.selectBaseCompanyById(companyId, tokenUser.getSiteId());
                    ParamException.notNull(childCompany, "分管单位id:" + companyId + "对应的单位不存在");

                    // 分管公司
                    GroupCompanyAddDTO groupCompanyAdd = new GroupCompanyAddDTO();
                    groupCompanyAdd.setGroupId(groupId);
                    groupCompanyAdd.setIsAll(false);
                    groupCompanyAdd.setCompanyId(companyId);
                    groupCompanyAddList.add(groupCompanyAdd);

                }
                // 发布分管公司
                groupCompanyService.batchSave(groupCompanyAddList, tokenUser);
            }
        }
    }

    /**
     * 移除组分管单位,分为删除数据,移除组子公司管理员身份
     *
     * @param groupId   组id
     * @param tokenUser 当前用户
     */
    private void removeGroupChildCompany(String groupId, TokenUser tokenUser) {
        // 现在的组分管单位
        List<GroupCompanyDO> groupCompanyList = groupCompanyService.listByGroupId(groupId, tokenUser.getSiteId());
        // 将组从子公司管理员移除
        if (!CollectionUtils.isEmpty(groupCompanyList)) {
            groupCompanyService.deleteByGroup(groupId, tokenUser);
        }
    }

    @Override
    public List<String> listGroupByUser(String userId, String siteId) {
        return groupUserService.findGroupIdsByUserId(userId, siteId);
    }

}
